package com.reggie.console.interceptor;

import com.reggie.common.enums.ResponseCode;
import com.reggie.common.exception.ReggieException;
import com.reggie.common.util.ReggieContext;
import com.reggie.console.annotation.AuthRule;
import com.reggie.console.enums.ReggieRole;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 接口权限校验拦截器
 *
 * @author yth
 * @since 2023-06-10-16:12
 */
@Slf4j
public class AuthInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        if (handler instanceof HandlerMethod) {
            setContextFromSession(request);
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            log.debug("权限校验：{}.{}", handlerMethod.getBeanType(), handlerMethod.getMethod());
            if (!predicateAuthByHandler(handlerMethod)) {
                log.info("拦截未登入请求：{}", request.getRequestURI());
                throw new ReggieException(ResponseCode.CLIENT_ERROR, "NOT_LOGIN");
            }
        }

        return true;
    }

    /**
     * <p根据调用的控制层方法，判断接口是否授权</p>
     * 如果方法上和类上都有@AuthRule注解，则取并集。
     *
     * @return true=授权，false=未授权
     */
    private boolean predicateAuthByHandler(HandlerMethod handlerMethod) {
        boolean isAuthorized = true;    // 如果没有设置权限校验，则默认有权限
        Method method = handlerMethod.getMethod();
        if (method.isAnnotationPresent(AuthRule.class)) {
            isAuthorized = false;
            AuthRule rule = method.getAnnotation(AuthRule.class);
            if (isAuthorized(rule.roles())) {
                return true;
            }
        }

        Class<?> controller = handlerMethod.getBeanType();
        if (controller.isAnnotationPresent(AuthRule.class)) {
            isAuthorized = false;
            AuthRule rule = controller.getAnnotation(AuthRule.class);
            if (isAuthorized(rule.roles())) {
                return true;
            }
        }
        return isAuthorized;
    }

    /**
     * 根据session设置context
     */
    private void setContextFromSession(HttpServletRequest request) {
        // 判断员工是否登入
        Object employeeId = request.getSession().getAttribute("employee");
        if (null != employeeId) {
            log.info("员工已登入：{}", request.getRequestURI());
            ReggieContext.getInstance().setEmployeeId((Long) employeeId);    // 存储id
        }
        // 判断用户是否登入
        Object userId = request.getSession().getAttribute("user");
        if (null != userId) {
            log.info("用户已登入：{}", request.getRequestURI());
            ReggieContext.getInstance().setUserId((Long) userId);    // 存储id
        }
    }

    /**
     * @param roles 角色列表
     * @return true=授权，false=未授权
     */
    private boolean isAuthorized(ReggieRole[] roles) {
        for (ReggieRole role : roles) {
            switch (role) {
                case CUSTOMER:
                    if (ReggieContext.getInstance().getUserId() == null) {
                        return false;
                    }
                    break;
                case EMPLOYEE:
                    if (ReggieContext.getInstance().getEmployeeId() == null) {
                        return false;
                    }
                    break;
                case MANAGER:
                    Long employeeId = ReggieContext.getInstance().getEmployeeId();
                    // Manager的id是 1L
                    if (employeeId == null || !employeeId.equals(1L)) {
                        return false;
                    }
                    break;
                default:
                    throw new ReggieException(ResponseCode.SYSTEM_ERROR, "不支持的权限角色");
            }
        }
        return true;
    }

}
